/*------------------------------------------------------------------------------
$module:      BaseTypes
$package:     CseApi
$purpose:     CSE Data type definition
$author:      WAYNE WORK STDIO
$CreateAt:    08/07/04
$LastModify:
$license:     Mozilla Public License Version 1.1
------------------------------------------------------------------------------*/

#include "CseApi_.h"

// declare local symbol
//==============================================================================
STATIC TBool AssertIsReady       = false;
STATIC TBool __CheckRefCount     = true;
STATIC TBool __HitBeforeExit     = false;
STATIC TUint32 CseObjectRefs[17] = {0,0,0,0,0, 0,0,0,0,0, 0,0,0,0,0, 0,0};

STATIC CseObj _ExistIDs          = NULL;

typedef TBool (*FreeObjFunc)(CseObj);
STATIC FreeObjFunc _FreeObjProc[17] = { NULL,NULL,NULL,NULL,NULL,
              NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL, NULL,NULL };

STATIC CseObj CseRegistTable    = NULL;
STATIC CseObj CsePreserves      = NULL;

STATIC CseObj CseTypeStrFunc    = NULL;
STATIC CseObj CseInstFreeFunc   = NULL;
STATIC CseObj CseInstCmpFunc    = NULL;
STATIC CseObj CseInstEqualFunc  = NULL;
STATIC CseObj CseInstStrFunc    = NULL;
STATIC CseObj CseInstBeStrFunc  = NULL;
STATIC CseObj CseInstAsKeyFunc  = NULL;
STATIC CseObj CseInstMapVarFunc = NULL;
STATIC CseObj CseLogErrorStack  = NULL;

CseObj CseBltinModule           = NULL;
CseObj CseMainModule            = NULL;

CseObj CseEmptySpace            = NULL;
CseObj CseThreadStacks          = NULL;
CseObj CseTraceStack            = NULL;

// Following define instance free len str asStr asNum mapVar
//==============================================================================
STATIC TCseException LogCseNotReady(void)
{
    return LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("CSE script system not ready"));
}

TBool GetCseTypeDesc(TCharArray& ret, CseObj value)
{
    TBool (*func)(TCharArray&,CseObj) = (TBool (*)(TCharArray&,CseObj)) CseTypeStrFunc->vValue;
    if (AssertIsReady && NULL != func)
        return func(ret,value);
    else return false;
}

void CseInstance_free(CseObj obj)
{
    void (*func)(CseObj) = (void (*)(CseObj)) CseInstFreeFunc->vValue;
    if (AssertIsReady && NULL != func) func(obj);
}

TInt CseInstance_cmp(CseObj obj1, CseObj obj2)
{
    if (AssertIsReady)
    {
        TInt (*func)(CseObj,CseObj) = (TInt (*)(CseObj,CseObj)) CseInstCmpFunc->vValue;
        if (NULL == func)
            throw LOG_CSE_ERR(CSE_SYNTAX_ERR,_T("instance comparison invalid"));

        return func(obj1,obj2);
    }
    else return (TInt) (obj1 - obj2);
}

TBool CseInstance_equal(CseObj obj1, CseObj obj2)
{
    if (AssertIsReady)
    {
        TBool (*func)(CseObj,CseObj) = (TBool (*)(CseObj,CseObj)) CseInstEqualFunc->vValue;
        if (NULL == func)
            throw LOG_CSE_ERR(CSE_SYNTAX_ERR,_T("instance comparison invalid"));
            
        return func(obj1,obj2);
    }
    else return obj1 == obj2;
}

CseObj CseInstance_str(CseObj obj)
{
    CseObj (*func)(CseObj) = (CseObj (*)(CseObj)) CseInstStrFunc->vValue;
    if (AssertIsReady && NULL != func)
        return func(obj);
    else return CseStr_new(TCharArray::format(_T("<instance:0x%X>"),obj));
}

CseObj CseInstance_BeStr(CseObj obj)
{
    CseObj (*func)(CseObj) = (CseObj (*)(CseObj)) CseInstBeStrFunc->vValue;
    if (AssertIsReady && NULL != func)
        return func(obj);
    else return CseStr_new(TCharArray::format(_T("<instance:0x%X>"),obj));
}

CseObj CseInstance_AsKey(CseObj obj)
{
    CseObj (*func)(CseObj) = (CseObj (*)(CseObj)) CseInstAsKeyFunc->vValue;
    if (AssertIsReady && NULL != func)
        return func(obj);
    else return Cse_IncRefEx(obj);
}

CseObj CseInstance_MapVar(TXchar flag, va_list& pArg)
{
    CseObj (*func)(TXchar,va_list&) = (CseObj (*)(TXchar,va_list&)) CseInstMapVarFunc->vValue;
    if (AssertIsReady && NULL != func)
        return func(flag,pArg);
    else throw LogCseNotReady();
}

// Following define TCseException
//==============================================================================
TCseException::TCseException(const TCseObj& ErrInfo)
{
    if (ErrInfo.type() != dtBuff || ErrInfo.len() == 0)
    {
        ErrorInfo = CseBuff_new(2);
        ErrorInfo->bValue[0] = CseId_new(UNKNOWN_SYS_ERR);
        ErrorInfo->bValue[1] = CseStr_new(CSE_UNDESC_ERROR);
    }
    else ErrorInfo = Cse_IncRefEx(ErrInfo);

    int iLen = Cse_len(ErrorInfo);
    ErrType = (iLen >= 1)? (const TXchar *) ErrorInfo->bValue[0]->sValue: NULL;
    ErrDesc = (iLen >= 2)? (const TXchar *) ErrorInfo->bValue[1]->sValue: NULL;
    ErrFlag = 0;
}

TCseException::TCseException(const TCseException& e)
{
    ErrorInfo = Cse_IncRefEx(e.ErrorInfo);

    int iLen = Cse_len(ErrorInfo);
    ErrType = (iLen >= 1)? (const TXchar *) ErrorInfo->bValue[0]->sValue: NULL;
    ErrDesc = (iLen >= 2)? (const TXchar *) ErrorInfo->bValue[1]->sValue: NULL;
    ErrFlag = 0;
}

TCseException::TCseException(const TCharArray& sErrType, const TCharArray& sErrDesc)
{
    ErrorInfo = CseBuff_new(2);
    ErrorInfo->bValue[0] = CseId_new(sErrType);
    ErrorInfo->bValue[1] = CseStr_new(sErrDesc);

    ErrType = (const TXchar *) ErrorInfo->bValue[0]->sValue;
    ErrDesc = (const TXchar *) ErrorInfo->bValue[1]->sValue;
    ErrFlag = 0;
}

TCseException::TCseException(const TCharArray& sErrType, const TCharArray& sErrDesc, const TCseObj& ErrArg)
{
    ErrorInfo = CseBuff_new(2);
    ErrorInfo->bValue[0] = CseId_new(sErrType);
    ErrorInfo->bValue[1] = CseStr_new(sErrDesc);
    CseBuff_append(ErrorInfo,ErrArg);

    ErrType = (const TXchar *) ErrorInfo->bValue[0]->sValue;
    ErrDesc = (const TXchar *) ErrorInfo->bValue[1]->sValue;
    ErrFlag = 0;
}

TCseException::~TCseException(void)
{
    Cse_DecRef(ErrorInfo);
}

void TCseException::setErrArg(const TCseObj& info) const
{
    int iLen = CSE_ARRAY_LEN(ErrorInfo->bValue);
    if (iLen >= 3)
        CseBuff_set(ErrorInfo,2,info);
    else if (iLen == 2)
        CseBuff_append(ErrorInfo,info);
    else
    {
        CseBuff_StolenAppend(ErrorInfo,CseStr_new(CSE_UNDESC_ERROR));
        CseBuff_append(ErrorInfo,info);
    }
}

TBool TCseException::isError(const TCharArray& ErrType) const
{
    if (CSE_ARRAY_LEN(ErrorInfo->bValue) > 0 && !ErrType.isEmpty())
    {
        TCharArray *s = (TCharArray *) &ErrorInfo->bValue[0]->sValue;
        return s->compare(ErrType) == 0;
    }
    else return false;
}

TCharArray TCseException::getErrType(void) const
{
    TCharArray *s = (TCharArray *) &ErrorInfo->bValue[0]->sValue;
    return *s;
}

TCharArray TCseException::getErrDesc(void) const
{
    if (CSE_ARRAY_LEN(ErrorInfo->bValue) >= 2)
    {
        TCharArray *s = (TCharArray *) &ErrorInfo->bValue[1]->sValue;
        return *s;
    }
    else return CSE_UNDESC_ERROR;
}

TCseObj TCseException::getErrArg(void) const
{
    if (CSE_ARRAY_LEN(ErrorInfo->bValue) >= 3)
        return ErrorInfo->bValue[2];
    else return dummy;
}

TCharArray TCseException::reportStr(void) const
{
    TCharArray *s = (TCharArray *) &ErrorInfo->bValue[0]->sValue;
    TCharArray desc = *s;
    desc += _T(": ");

    if (CSE_ARRAY_LEN(ErrorInfo->bValue) >= 2)
    {
        TCharArray *s2 = (TCharArray *) &ErrorInfo->bValue[1]->sValue;
        desc += *s2;
    }
    else desc += CSE_UNDESC_ERROR;

    return desc;
}

TCseObj TCseException::getErrInfo() const
{
    return ErrorInfo;
}

TCseException Cse_LogError(const TCseException& err)
{
    LogErrNameAndDesc(err.getErrType(),err.getErrDesc());

    if (CseLogErrorStack != NULL && CseLogErrorStack->vValue != NULL)
    {
        void (*func)(CseObj stack,const TCseException& err) = (void (*)(CseObj,const TCseException&)) CseLogErrorStack->vValue;
        func(CseTraceStack,err);
    }
    return err;
}

TBool Cse_AssertMsg(int expr, const TXchar *msg)
{
    if (!expr)
    {
        if (AssertIsReady)
            throw LOG_CSE_ERR(CSE_ASSERT_ERR,msg);
        else throw msg;
    }
    return true;
}

TBool Cse_AssertMsg2(int expr, int iLine, const TXchar *sFile)
{
    if (!expr)
    {
        TCharArray sDesc = TCharArray::format(_T("assert failed at line %d in %s"),iLine,sFile);

        if (AssertIsReady)
            throw LOG_CSE_ERR(CSE_ASSERT_ERR,sDesc);
        else throw sDesc.addr();
    }
    return true;
}

TCseException Cse_WaitToDo(int line, const TXchar *sFile)
{
    return LOG_CSE_ERR(CSE_NOTIMP_ERR,TCharArray::format(_T("waiting to do at line %d in %s"),line,sFile));
}

// Following define TStolenObj
//==============================================================================
TStolenObj::TStolenObj()
{
    m_obj = dummy;
}

TStolenObj::~TStolenObj()
{
    Cse_DecRef(m_obj);
}

TStolenObj::TStolenObj(CseObj obj)
{
    m_obj = obj;
}

void TStolenObj::bind(CseObj obj)
{
    Cse_DecRef(m_obj);
    m_obj = obj;
}

CseObj TStolenObj::operator->() const
{
    return m_obj;
}

TStolenObj::operator CseObj() const
{
    return m_obj;
}

// Following define common CSE object API
//==============================================================================
void Cse_CloseRefCheck(void)
{
    __CheckRefCount = false;
}

void Cse_HitWhenExit(void)
{
    __HitBeforeExit = true;
}

void Cse_IncRef(CseObj obj)
{
    if (obj == dummy || obj == NULL) return;
    TUint32 *pRef = (TUint32 *) ((char *)obj - CSEOBJ_INNER_OFFSET);

    if (0 == *pRef)
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("increase zero RefCount"));
    (*pRef)++;
}

void Cse_DecRef(CseObj obj)
{
    if (obj == dummy || obj == NULL) return;
    TUint32 *pRef = (TUint32 *)((char *)obj - CSEOBJ_INNER_OFFSET);

    if (0 == *pRef)
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("decrease zero RefCount"));

    (*pRef)--;
    if (0 == *pRef)
    {
        int tp = Cse_type(obj);
        if (tp < dtNotator)
        {
            if (_FreeObjProc[tp](obj))
                CseObjectRefs[tp]--;
        }
        else
        {
            if (_FreeObjProc[dtNotator](obj))
                CseObjectRefs[dtNotator]--;
        }
    }
}

CseObj Cse_IncRefEx(CseObj obj)
{
    Cse_IncRef(obj);
    return obj;
}

TUint32 Cse_RefCount(CseObj obj)
{
    return *(TUint32 *)((char *)obj - CSEOBJ_INNER_OFFSET);
}

int Cse_type(CseObj obj)
{
    TInt8 *byteVal = (TInt8 *)((char *)obj - CSEOBJ_TYPE_OFFSET);
    return *byteVal;
}

int Cse_len(CseObj value)
{
    int tp = Cse_type(value);
    if ( dtBuff == tp || tp >= dtNotator || dtStr == tp || dtTier == tp ||
         dtInstance == tp || dtId == tp)
        return CSE_ARRAY_LEN(value->sValue);
    else if (dtDict == tp)
    {
        if (value->entry == NULL)
            return 0;
        else return CSE_ARRAY_LEN(value->sValue);
    }
    else throw LOG_CSE_ERR(CSE_SYNTAX_ERR,_T("invalid len(obj)"));
}

TBool Cse_FixSize(CseObj value, int iResvd)
{
    int tp = Cse_type(value);

    if (dtDict == tp)
    {
        int iFixedSize = CSE_ARRAY_LEN(value->entry) + iResvd;
        if (value->iFix != 0)
        {
            if (value->iFix < iFixedSize)
                throw LOG_CSE_ERR(CSE_RANGE_ERR,_T("dict size already fixed"));
            value->iFix = iFixedSize;
            return true;
        }
        else
        {
            TEntryArray *pArray = (TEntryArray *) &value->entry;
            pArray->fixSize(iResvd);
            value->iFix = iFixedSize;
            return true;
        }
    }
    else if (dtStr == tp || dtTier == tp || dtBuff == tp)
    {
        if (value->iFix != 0)
            throw LOG_CSE_ERR(CSE_SYNTAX_ERR,_T("CSE array already fixed"));
        value->iFix = CSE_ARRAY_LEN(value->sValue) + iResvd;
        return true;
    }
    else return false;
}

TUint32 Cse_hash(CseObj obj)
{
    int tp = Cse_type(obj);

    if (tp == dtInt)
        return (TUint32) obj->iValue;
    else if (tp == dtId)
        return (TUint32) obj->hash;
    else if (tp == dtStr)
    {
        TCharArray *s = (TCharArray *) &obj->sValue;
        return s->hash();
    }
    else if (tp == dtFloat || tp == dtWint)
        return (TUint32)(obj->iValue ^ obj->iFlag);
    else return (TUint32)obj;
}

STATIC TInt BaseDataCompare(int tp1, CseObj v1, int tp2, CseObj v2)
{
    if (tp1 == dtInt)
    {
        if (tp2 == dtInt)
            return v1->iValue - v2->iValue;
        else if (tp2 == dtWint)
        {
            if ((TWint)v1->iValue > v2->wValue)
                return 1;
            else if ((TWint)v1->iValue == v2->wValue)
                return 0;
            else return -1;
        }
        else
        {
            ASSERT_TRUE(tp2 == dtFloat);
            if ((TDouble)v1->iValue > v2->fValue)
                return 1;
            else if ((TDouble)v1->iValue == v2->fValue)
                return 0;
            else return -1;
        }
    }
    else if (tp1 == dtWint)
    {
        if (tp2 == dtInt)
        {
            if (v1->wValue > (TWint)v2->iValue)
                return 1;
            else if (v1->wValue == (TWint)v2->iValue)
                return 0;
            else return -1;
        }
        else if (tp2 == dtWint)
        {
            if (v1->wValue > v2->wValue)
                return 1;
            else if (v1->wValue == v2->wValue)
                return 0;
            else return -1;
        }
        else
        {
            ASSERT_TRUE(tp2 == dtFloat);
            if ((TDouble)v1->wValue > v2->fValue)
                return 1;
            else if ((TDouble)v1->wValue == v2->fValue)
                return 0;
            else return -1;
        }
    }
    else
    {
        ASSERT_TRUE(tp1 == dtFloat);
        if (tp2 == dtInt)
        {
            if (v1->fValue > (TDouble)v2->iValue)
                return 1;
            else if (v1->fValue == (TDouble)v2->iValue)
                return 0;
            else return -1;
        }
        else if (tp2 == dtWint)
        {
            if (v1->fValue > (TDouble)v2->wValue)
                return 1;
            else if (v1->fValue == (TDouble)v2->wValue)
                return 0;
            else return -1;
        }
        else
        {
            ASSERT_TRUE(tp2 == dtFloat);
            if (v1->fValue > v2->fValue)
                return 1;
            else if (v1->fValue == v2->fValue)
                return 0;
            else return -1;
        }
    }
}

TInt Cse_ObjComp(CseObj obj1, CseObj obj2, int tp2)
{
    int tp1 = Cse_type(obj1);

    if (tp1 != tp2)
    {
        if (tp1 == dtInstance || tp2 == dtInstance)
            return CseInstance_cmp(obj1,obj2);
        else if (tp1 <= 2 && tp2 <= 2)  // compare between dtInt, dtWint, dtFloat
            return BaseDataCompare(tp1,obj1,tp2,obj2); // 2 == 2.0,  2W = 2.0 ...
        else return tp1 - tp2;
    }
    else  // tp1 == tp2
    {
        if (tp1 == dtStr || tp1 == dtId)
        {
            if (obj1 == obj2) return 0;

            TCharArray *pObj1 = (TCharArray *) &obj1->sValue;
            TCharArray *pObj2 = (TCharArray *) &obj2->sValue;
            return pObj1->compare(*pObj2);
        }
        else if (tp1 == dtInt)
            return (TInt) (obj1->iValue - obj2->iValue);
        else if (tp1 == dtBuff || tp1 >= dtNotator)
        {
            if (obj1 == obj2) return 0;

            TObjArray *pObj1 = (TObjArray *) &obj1->bValue;
            TObjArray *pObj2 = (TObjArray *) &obj2->bValue;
            return pObj1->compare(*pObj2);
        }
        else if (tp1 == dtTier)
        {
            if (obj1 == obj2) return 0;

            TIntArray *pObj1 = (TIntArray *) &obj1->tValue;
            TIntArray *pObj2 = (TIntArray *) &obj2->tValue;
            return pObj1->compare(*pObj2);
        }
        else if (tp1 == dtInstance)
        {
            return CseInstance_cmp(obj1,obj2);
        }
        else if (tp1 == dtFloat)
        {
            if (obj1->fValue == obj2->fValue)
                return 0;
            else if (obj1->fValue > obj2->fValue)
                return 1;
            else return -1;
        }
        else if (tp1 == dtWint)
        {
            if (obj1->wValue == obj2->wValue)
                return 0;
            else if (obj1->wValue > obj2->wValue)
                return 1;
            else return -1;
        }
        else if (tp1 == dtStrong)
            return Cse_ObjComp(obj1->vValue,obj2->vValue,Cse_type(obj2->vValue));
        else if (tp1 == dtWeak)
            return (TInt) (obj1->vValue - obj2->vValue);
        else return (TInt) ((TInt)obj1 - (TInt)obj2);
    }
}

TInt Cse_compare(CseObj self, CseObj other)
{
    return Cse_ObjComp(self,other,Cse_type(other));
}

TBool Cse_equal(CseObj self, CseObj other)
{
    if (self == other)
        return true;
    else
    {
        int tp1 = Cse_type(self);
        int tp2 = Cse_type(other);
        if (tp1 == dtInstance || tp2 == dtInstance)
            return CseInstance_equal(self,other);
        else return 0 == Cse_ObjComp(self,other,tp2);
    }
}

TInt32 Cse_GetFlag(CseObj obj)
{
    return *(TInt32 *)((char *)obj - CSEOBJ_TYPE_OFFSET);
}

void Cse_SetFlag(CseObj obj, TInt32 flag)
{
    // reserve low-8-bits, and set high 24 bits
    flag = flag & 0xFFFFFF00;
    TInt32 *pFlag = (TInt32 *)((TInt8 *)obj - CSEOBJ_TYPE_OFFSET);
    *pFlag = (*pFlag & 0xFF) | flag;
}

TBool Cse_OptionOn(CseObj value, int iOffset)
{
    TInt32 flag = (0x01 << iOffset) & (*(TInt32 *)((char *)value - CSEOBJ_TYPE_OFFSET));
    return flag != 0;
}

void Cse_SetOption(CseObj value, int iOffset)
{
    ASSERT_TRUE(iOffset >= 8);
    TInt32 *pFlag = (TInt32 *)((TInt8 *)value - CSEOBJ_TYPE_OFFSET);
    *pFlag = (*pFlag) | (1 << iOffset);
}

void Cse_ClearOption(CseObj value, int iOffset)
{
    ASSERT_TRUE(iOffset >= 8);
    TInt32 *pFlag = (TInt32 *)((TInt8 *)value - CSEOBJ_TYPE_OFFSET);
    *pFlag = (*pFlag) & ((1 << iOffset) ^ 0xFFFFFFFF);
}

const TXchar *Cse_GetTypeName(int tp)
{
    switch(tp)
    {
        case dtInt:      return _T("int");
        case dtWint:     return _T("wint");
        case dtFloat:    return _T("float");
        case dtStr:      return _T("string");
        case dtTier:     return _T("tier");
        case dtBuff:     return _T("buff");
        case dtDict:     return _T("dict");
        case dtInstance: return _T("instance");
        case dtId:       return _T("ID");
        case dtStrong:   return _T("strong");
        case dtWeak:     return _T("weak");
        case dtNotator:  return _T("notator");
        default:         return _T("unknown");
    }
}

CseObj Cse_unlink(CseObj value)
{
    if (Cse_OptionOn(value,CSEOBJ_LINKED))
    {   // if linked, it must be mapped
        ASSERT_TRUE(Cse_type(value) == dtInstance);

        // can not recursive linked
        ASSERT_TRUE(! Cse_OptionOn(value->bValue[1],CSEOBJ_LINKED));
        return value->bValue[1];
    }
    else return value;
}

STATIC void Cse_FuncDesc(TCharArray& ret, int tp, CseObj FuncId)
{
    if (tp == CSE_ATOMCALL_FLAG)
    {
        TInt8 flag = (TInt8)FuncId->bFlag.b1;
        switch(flag & 0x0F)
        {
        case dsIterCdecl:   ret = _T("IterCdecl");   break;
        case dsIterStdcall: ret = _T("IterStdcall"); break;
        case dsIterScript:  ret = _T("IterScript");  break;
        case dsFrmtScript:  ret = _T("FrmtScript");  break;
        case dsPostCdecl:   ret = _T("PostCdecl");   break;
        case dsPostStdcall: ret = _T("PostStdcall"); break;
        default: ret = _T("unknown");
        }
    }

    else Cse_str(ret,FuncId);
}

STATIC void Cse_GetRecursiveDesc(CseObj value, TCharArray& ret)
{
    ret = TCharArray::format(_T("<recursive:0x%X>"),value);
}

STATIC TBool GetStrObjValue(TCharArray& ret, CseObj value, TBool beStr=false)
{
    if (CSE_ARRAY_LEN(value->bValue) >= 2 && value->bValue[0] == CppStrType)
    {
        CseObj v = value->bValue[1];
        int tp = Cse_type(v);
        if (tp == dtInt)
        {
            TCharArray *pCh = (TCharArray *) v->iValue;
            if (pCh == NULL)
                ret = _T("<NULL>");
            else ret = *pCh;
            return true;
        }
        else if (tp == dtStrong)
        {
            if (beStr)
                Cse_BeStr(ret,v->vValue);
            else Cse_str(ret,v->vValue);
            return true;
        }
    }
    return false;
}

void Cse_str(TCharArray& ret, CseObj value)
{
    int tp = Cse_type(value);
    int id = 0;

    if (tp == dtInstance)
    {
        if (! Cse_OptionOn(value,CSEOBJ_STR_FLAG))
        {
            Cse_SetOption(value,CSEOBJ_STR_FLAG);
            try
            {
                if (GetStrObjValue(ret,value)) return;

                CseObj v = CseInstance_str(value);
                if (NULL != v)
                {
                    tp = Cse_type(v);
                    if (dtStr == tp || dtId == tp)
                    {
                        TCharArray *s = (TCharArray *) &v->sValue;
                        ret = *s;
                    }
                    else if (dtInstance == tp && GetStrObjValue(ret,v))
                    {
                        Cse_DecRef(v);
                        return;
                    }
                    else ret = TCharArray::format(_T("<instance:0x%X>"),value);
                    Cse_DecRef(v);
                }
                else ret = TCharArray::format(_T("<instance:0x%X>"),value);
            }
            catch(...)
            {
                Cse_ClearOption(value,CSEOBJ_STR_FLAG);
                throw;
            }
            Cse_ClearOption(value,CSEOBJ_STR_FLAG);
        }
        else Cse_GetRecursiveDesc(value,ret);
    }

    else if ( (id = (Cse_GetFlag(value) >> 16) & 0x0F) != 0 )
    {
        if (! GetCseTypeDesc(ret,value))
            ret = TCharArray::format(_T("<type:0x%X>"),value);
    }

    else if (tp >= dtNotator)
    {
        if (! Cse_OptionOn(value,CSEOBJ_STR_FLAG))
        {
            Cse_SetOption(value,CSEOBJ_STR_FLAG);
            try
            {
                TCharArray sDesc;
                Cse_FuncDesc(sDesc,tp,value->bValue[0]);
                ret = _T('<') + sDesc + _T(":>");
            }
            catch(...)
            {
                Cse_ClearOption(value,CSEOBJ_STR_FLAG);
                throw;
            }
            Cse_ClearOption(value,CSEOBJ_STR_FLAG);
        }
        else Cse_GetRecursiveDesc(value,ret);
    }

    else if (tp == dtInt)
        ret = TCharArray::format(_T("%d"),value->iValue);

    else if (tp == dtStr)
    {
        TCharArray *s = (TCharArray *) &value->sValue;
        ret = s->str();
    }
    
    else if (tp == dtId)
    {
        TCharArray *s = (TCharArray *) &value->sValue;
        ret = *s;  // copy transfer
    }

    else if (tp == dtTier)
    {
        TIntArray *t = (TIntArray *) &value->tValue;
        ret = t->str();
    }

    else if (tp == dtBuff)
    {
        if (! Cse_OptionOn(value,CSEOBJ_STR_FLAG))
        {
            Cse_SetOption(value,CSEOBJ_STR_FLAG);
            try
            {
                TObjArray *b = (TObjArray *) &value->bValue;
                ret = b->str();
            }
            catch(...)
            {
                Cse_ClearOption(value,CSEOBJ_STR_FLAG);
                throw;
            }
            Cse_ClearOption(value,CSEOBJ_STR_FLAG);
        }
        else Cse_GetRecursiveDesc(value,ret);
    }

    else if (tp == dtDict)
    {
        if (! Cse_OptionOn(value,CSEOBJ_STR_FLAG))
        {
            Cse_SetOption(value,CSEOBJ_STR_FLAG);
            try
            {
                TEntryArray *d = (TEntryArray *) &value->entry;
                ret = d->str();
            }
            catch(...)
            {
                Cse_ClearOption(value,CSEOBJ_STR_FLAG);
                throw;
            }
            Cse_ClearOption(value,CSEOBJ_STR_FLAG);
        }
        else Cse_GetRecursiveDesc(value,ret);
    }

    else if (tp == dtWint)
        ret = TCharArray::format(_T("%" CseLongLongFmtSpec _T("dW")),value->wValue);

    else if (tp == dtFloat)
    {
        if (value->fValue == 0.0)
            ret = _T("0.0");
        else if (value->fValue < 0.00001 || value->fValue > 100000.0)
        {   // too small or too large, use "nnExx" format
            ret = TCharArray::format(_T("%.8e"),value->fValue);
        }
        else
        {
            ret = TCharArray::format(_T("%.8f"),value->fValue);
            int iDotFrom = ret.find(_T('.'));
            if (iDotFrom >= 0)
            {
                while (ret[-1] == _T('0')) ret.remove(-1);
                if (ret.len() == iDotFrom + 1) ret += _T('0');
            }
        }
    }

    else if (tp == dtWeak)
        ret = TCharArray::format(_T("<weak:0x%X>"),value->vValue);

    else if (tp == dtStrong)
        ret = TCharArray::format(_T("<strong:0x%X>"),value->vValue);

    else throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("type error in Cse_str()"));
}

void Cse_StrEx(CseObj sOut, CseObj value)
{
    TCharArray s;
    Cse_str(s,value);
    sOut->sValue = s.transfer(sOut->sValue);
}

void Cse_BeStr(TCharArray& ret, CseObj obj)
{
    int tp = Cse_type(obj);
    if (dtId == tp || dtStr == tp)
    {
        ret = *(TCharArray *) &obj->sValue;  // copy string
    }
    else Cse_str(ret,obj);
}

// Following define CSE data access functions
//==============================================================================
CseObj CseInt_new(TInt initVal, TInt flag)
{
    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtInt;
    pRes->context.iValue = initVal;
    pRes->context.iFlag  = flag;

    CseObjectRefs[dtInt]++;
    return (CseObj) &pRes->context;
}

CseObj CseWint_new(TWint initVal)
{
    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtWint;
    pRes->context.wValue = initVal;

    CseObjectRefs[dtWint]++;
    return (CseObj) &pRes->context;
}

CseObj CseFloat_new(TDouble initVal)
{
    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtFloat;
    pRes->context.fValue = initVal;

    CseObjectRefs[dtFloat]++;
    return (CseObj) &pRes->context;
}

CseObj CseStr_new(const TXchar *sValue, int iLen)
{
    TCharArray newStr = TCharArray(sValue,iLen);

    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtStr;
    pRes->context.sValue = newStr.transfer(NULL);
    pRes->context.iFix  = 0;  // means dynamic size

    CseObjectRefs[dtStr]++;
    return (CseObj) &pRes->context;
}

CseObj CseStr_new(const TCharArray& sValue)
{
    TCharArray newStr = TCharArray(sValue);

    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtStr;
    pRes->context.sValue = newStr.transfer(NULL);
    pRes->context.iFix = 0;  // means dynamic size

    CseObjectRefs[dtStr]++;
    return (CseObj) &pRes->context;
}

CseObj CseStr_NewEx(TCharArray& sValue)
{
    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtStr;
    pRes->context.sValue = sValue.transfer(NULL); // transfer the buffer in sValue
    pRes->context.iFix = 0;  // means dynamic size

    CseObjectRefs[dtStr]++;
    return (CseObj) &pRes->context;
}

STATIC TCseException LogIndexOutRangeErr(int tp = dtNull)
{
    TCharArray sDesc = _T("index out of range");
    if (tp == dtNull)
        return LOG_CSE_ERR(CSE_RANGE_ERR,sDesc);
    else
    {
        if (tp > dtNotator) tp = dtNotator;
        return LOG_CSE_ERR(CSE_RANGE_ERR,Cse_GetTypeName(tp) + _T(' ') + sDesc);
    }
}

TXchar CseStr_append(CseObj str, TXchar ch, int *pIndex)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);
    TCharArray *s = (TCharArray *)&str->sValue;
    s->add(ch,pIndex);
    return ch;
}

TXchar CseStr_get(CseObj str, int index)
{
    TCharArray *s = (TCharArray *)&str->sValue;
    return (*s)[index];
}

void CseStr_set(CseObj str, int index, TXchar ch)
{
    TCharArray *s = (TCharArray *)&str->sValue;
    (*s)[index] = ch;
}

void CseStr_insert(CseObj str, int index, TXchar ch)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *s = (TCharArray *)&str->sValue;
    s->insert(index,ch);
}

CseObj CseStr_slice(CseObj str, int index, int count)
{
    TCharArray *s = (TCharArray *)&str->sValue;
    TCharArray s2 = s->slice(index,count);
    return CseStr_NewEx(s2);
}

void CseStr_remove(CseObj str, int index, int count)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *s = (TCharArray *)&str->sValue;
    s->remove(index,count);
}

void CseStr_clear(CseObj str)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *s = (TCharArray *)&str->sValue;
    s->clear();  // free old buffer
}

void CseStr_assign(CseObj TargStr, const TCharArray& SourStr)
{
    if (TargStr->iFix != 0)
    {   // fix size string
        if ((int) CSE_ARRAY_LEN(TargStr->sValue) != SourStr.len())
            throw LogIndexOutRangeErr(dtStr);
    }

    TCharArray *sTarg = (TCharArray *)&TargStr->sValue;
    *sTarg = SourStr;
}

void CseStr_assign(CseObj TargStr, CseObj SourStr)
{
    ASSERT_TRUE(SourStr != NULL);
    TCharArray *sSour = (TCharArray *)&SourStr->sValue;
    CseStr_assign(TargStr,*sSour);
}

void CseStr_join(CseObj TargStr, const TCharArray& SourStr, int index)
{
    if (TargStr->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *sTarg = (TCharArray *)&TargStr->sValue;
    sTarg->join(SourStr,index);
}

void CseStr_join(CseObj TargStr, CseObj SourStr, int index)
{
    ASSERT_TRUE(SourStr != NULL);
    if (TargStr->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);
        
    TCharArray *sSour = (TCharArray *)&SourStr->sValue;
    TCharArray *sTarg = (TCharArray *)&TargStr->sValue;
    sTarg->join(*sSour,index);
}

int CseStr_SortAdd(CseObj str, TXchar ch)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *sTarg = (TCharArray *)&str->sValue;
    return sTarg->sortAdd(ch);
}

void CseStr_sort(CseObj str)
{
    TCharArray *sTarg = (TCharArray *)&str->sValue;
    sTarg->sort();
}

void CseStr_upper(CseObj str)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    sTarg->upper();
}

void CseStr_lower(CseObj str)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    sTarg->lower();
}

void CseStr_trim(CseObj str)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    sTarg->trim();
}

void CseStr_TrimLeft(CseObj str)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *sTarg = (TCharArray *) &str->sValue;
    sTarg->trimLeft();
}

void CseStr_TrimRight(CseObj str)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    TCharArray *sTarg = (TCharArray *) &str->sValue;
    sTarg->trimRight();
}

int CseStr_truncate(CseObj str, int iLen)
{
    if (str->iFix != 0)
        throw LogIndexOutRangeErr(dtStr);

    // truncate not realloc buffer, but clear do
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    return sTarg->truncate(iLen);
}

TUint32 CseStr_hash(CseObj str)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    return sTarg->hash();
}

int CseStr_find(CseObj str, TXchar ch, TBool fromEnd)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    return sTarg->find(ch,fromEnd);
}

int CseStr_find(CseObj str, const TXchar *sSub, int from)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    return sTarg->find(sSub,from);
}

CseObj CseStr_ToInt(CseObj str)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    TInt i;
    if (sTarg->toInt(i))
        return CseInt_new(i);
    else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("translate string to int error"));
}

CseObj CseStr_ToWInt(CseObj str)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    TInt64 i;
    if (sTarg->toWInt(i))
        return CseWint_new(i);
    else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("translate string to wint error"));
}

CseObj CseStr_ToDouble(CseObj str)
{
    TCharArray *sTarg = (TCharArray *) &str->sValue;
    TDouble f;
    if (sTarg->toDouble(f))
        return CseFloat_new(f);
    else throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("translate string to float error"));
}

CseObj CseTier_new(int iSize)
{
    TIntArray newTier = TIntArray(iSize);

    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtTier;
    pRes->context.tValue = newTier.transfer(NULL);
    pRes->context.iFix = 0;  // means dynamic size

    CseObjectRefs[dtTier]++;
    return (CseObj) &pRes->context;
}

CseObj CseTier_new(const TIntArray& tValue)
{
    TIntArray newTier = TIntArray(tValue);

    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtTier;
    pRes->context.tValue = newTier.transfer(NULL);
    pRes->context.iFix = 0;  // means dynamic size

    CseObjectRefs[dtTier]++;
    return (CseObj) &pRes->context;
}

CseObj CseTier_NewEx(TIntArray& tValue)
{
    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtTier;
    pRes->context.tValue = tValue.transfer(NULL); // transfer buffer
    pRes->context.iFix = 0;  // means dynamic size

    CseObjectRefs[dtTier]++;
    return (CseObj) &pRes->context;
}

TInt CseTier_append(CseObj tier, TInt value, int *pIndex)
{
    if (tier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);

    TIntArray *t = (TIntArray *)&tier->tValue;
    t->add(value,pIndex);
    return value;
}

TInt CseTier_get(CseObj tier, int index)
{
    TIntArray *t = (TIntArray *)&tier->tValue;
    return (*t)[index];
}

void CseTier_set(CseObj tier, int index, TInt value)
{
    TIntArray *t = (TIntArray *)&tier->tValue;
    (*t)[index] = value;
}

void CseTier_insert(CseObj tier, int index, TInt value)
{
    TIntArray *t = (TIntArray *) &tier->tValue;
    if (tier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);
    t->insert(index,value);
}

CseObj CseTier_slice(CseObj tier, int index, int count)
{
    TIntArray *t = (TIntArray *) &tier->tValue;
    TIntArray t2 = t->slice(index,count);
    return CseTier_NewEx(t2);
}

void CseTier_remove(CseObj tier, int index, int count)
{
    TIntArray *t = (TIntArray *)&tier->tValue;
    if (tier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);
    t->remove(index,count);
}

void CseTier_clear(CseObj tier)
{
    if (tier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);

    TIntArray *t = (TIntArray *)&tier->tValue;
    t->clear();
}

void CseTier_assign(CseObj TargTier, const TIntArray& SourTier)
{
    if (TargTier->iFix != 0)
    {   // fix size tier
        if ((int) CSE_ARRAY_LEN(TargTier->tValue) != SourTier.len())
            throw LogIndexOutRangeErr(dtTier);
    }

    TIntArray *tTarg = (TIntArray *)&TargTier->tValue;
    *tTarg = SourTier;
}

void CseTier_assign(CseObj TargTier, CseObj SourTier)
{
    ASSERT_TRUE(SourTier != NULL);
    TIntArray *tSour = (TIntArray *)&SourTier->tValue;
    CseTier_assign(TargTier,*tSour);
}

void CseTier_join(CseObj TargTier, const TIntArray& SourTier, int index)
{
    if (TargTier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);

    TIntArray *tTarg = (TIntArray *)&TargTier->tValue;
    tTarg->join(SourTier,index);
}

void CseTier_join(CseObj TargTier, CseObj SourTier, int index)
{
    ASSERT_TRUE(SourTier != NULL);
    if (TargTier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);

    TIntArray *tSour = (TIntArray *)&SourTier->tValue;
    TIntArray *tTarg = (TIntArray *)&TargTier->tValue;
    tTarg->join(*tSour,index);
}

int CseTier_SortAdd(CseObj tier, TInt value)
{
    if (tier->iFix != 0)
        throw LogIndexOutRangeErr(dtTier);

    TIntArray *tTarg = (TIntArray *)&tier->tValue;
    return tTarg->sortAdd(value);
}

void CseTier_sort(CseObj tier)
{
    TIntArray *tTarg = (TIntArray *)&tier->tValue;
    tTarg->sort();
}

int CseTier_truncate(CseObj tier, int iLen)
{
    TIntArray *tTarg = (TIntArray *)&tier->tValue;
    return tTarg->truncate(iLen);
}

CseObj CseBuff_new(int iSize)
{
    TObjArray newBuff = TObjArray(iSize);

    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtBuff;
    pRes->context.bValue = newBuff.transfer(NULL);
    pRes->context.iFix  = 0;  // means dynamic size

    CseObjectRefs[dtBuff]++;
    return (CseObj) &pRes->context;
}

CseObj CseBuff_new(const TObjArray& bValue)
{
    TObjArray newBuff = TObjArray(bValue);

    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtBuff;
    pRes->context.bValue = newBuff.transfer(NULL);
    pRes->context.iFix  = 0;  // means dynamic size

    CseObjectRefs[dtBuff]++;
    return (CseObj) &pRes->context;
}

CseObj CseBuff_NewEx(TObjArray& bValue)
{
    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtBuff;
    pRes->context.bValue = bValue.transfer(NULL);
    pRes->context.iFix  = 0;  // means dynamic size

    CseObjectRefs[dtBuff]++;
    return (CseObj) &pRes->context;
}

CseObj CseBuff_StolenAppend(CseObj buff, CseObj obj)
{
    ASSERT_TRUE(obj != NULL);
    if (buff->iFix != 0)
    {
        Cse_DecRef(obj);
        throw LogIndexOutRangeErr(dtBuff);
    }
    
    TObjArray *b = (TObjArray *) &buff->bValue;
    b->append(obj);
    Cse_DecRef(obj);
    return obj;
}

CseObj CseBuff_append(CseObj buff, CseObj obj, int *pIndex)
{
    ASSERT_TRUE(obj != NULL);
    if (buff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);
        
    TObjArray *b = (TObjArray *) &buff->bValue;
    b->add(obj,pIndex);
    return obj;
}

CseObj CseBuff_get(CseObj buff, int index)
{
    TObjArray *b = (TObjArray *) &buff->bValue;
    return (*b)[index];
}

void CseBuff_set(CseObj buff, int index, CseObj value)
{
    ASSERT_TRUE(value != NULL);
    TObjArray *b = (TObjArray *) &buff->bValue;
    (*b)[index] = value;
}

void CseBuff_insert(CseObj buff, int index, CseObj value)
{
    ASSERT_TRUE(value != NULL);
    TObjArray *b = (TObjArray *) &buff->bValue;

    if (buff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);
    b->insert(index,value);
}

CseObj CseBuff_slice(CseObj buff, int index, int count)
{
    TObjArray *b = (TObjArray *) &buff->bValue;
    TObjArray b2 = b->slice(index,count);
    return CseBuff_NewEx(b2);
}

void CseBuff_remove(CseObj buff, int index, int count)
{
    TObjArray *b = (TObjArray *) &buff->bValue;
    if (buff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);
    b->remove(index,count);
}

void CseBuff_clear(CseObj buff)
{
    if (buff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);

    TObjArray *b = (TObjArray *)&buff->bValue;
    b->clear();
}

void CseBuff_assign(CseObj TargBuff, const TObjArray& SourBuff)
{
    if (TargBuff->iFix != 0)
    {   // fix size buff
        if ((int) CSE_ARRAY_LEN(TargBuff->bValue) != SourBuff.len())
            throw LogIndexOutRangeErr(dtBuff);
    }

    TObjArray *bTarg = (TObjArray *)&TargBuff->bValue;
    *bTarg = SourBuff;
}

void CseBuff_assign(CseObj TargBuff, CseObj SourBuff)
{
    ASSERT_TRUE(SourBuff != NULL);
    TObjArray *bSour = (TObjArray *)&SourBuff->bValue;
    CseBuff_assign(TargBuff,*bSour);
}

void CseBuff_join(CseObj TargBuff, const TObjArray& SourBuff, int index)
{
    if (TargBuff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);

    TObjArray *bTarg = (TObjArray *)&TargBuff->bValue;
    bTarg->join(SourBuff,index);
}

void CseBuff_join(CseObj TargBuff, CseObj SourBuff, int index)
{
    ASSERT_TRUE(SourBuff != NULL);
    if (TargBuff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);

    TObjArray *bSour = (TObjArray *)&SourBuff->bValue;
    TObjArray *bTarg = (TObjArray *)&TargBuff->bValue;
    bTarg->join(*bSour,index);
}

int CseBuff_SortAdd(CseObj buff, CseObj obj)
{
    ASSERT_TRUE(obj != NULL);
    if (buff->iFix != 0)
        throw LogIndexOutRangeErr(dtBuff);

    TObjArray *bTarg = (TObjArray *)&buff->bValue;
    return bTarg->sortAdd(obj);
}

void CseBuff_sort(CseObj buff)
{
    TObjArray *bTarg = (TObjArray *)&buff->bValue;
    bTarg->sort();
}

int CseBuff_truncate(CseObj buff, int iLen)
{
    TObjArray *bTarg = (TObjArray *)&buff->bValue;
    return bTarg->truncate(iLen);
}

CseObj CseBuff_ToNotator(CseObj buff, int index)
{
    ASSERT_TRUE(index >= 0);
    CseObj ret = CseBuff_new(0);
    
    TObjArray *pTarg = (TObjArray *) &ret->bValue;
    TObjArray *pSour = (TObjArray *) &buff->bValue;
    pTarg->join(*pSour,index);
    
    if (pTarg->len() <= 0)
    {
        Cse_DecRef(ret);
        throw LOG_CSE_ERR(CSE_VALUE_ERR,_T("can not convert empty buff to notator"));
    }

    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)ret - CSEOBJ_INNER_OFFSET);
    int tp = Cse_type((*pTarg)[0]);
    if (tp >= dtNotator)
        pBase->DataType = dtNotator + dtNull;
    else pBase->DataType = dtNotator + tp;

    CseObjectRefs[dtBuff]--;
    CseObjectRefs[dtNotator]++;
    return ret;
}

CseObj CseDict_new(int size)
{
    TEntryArray newDict = TEntryArray(size);

    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtDict;
    pRes->context.entry = newDict.transfer(NULL);
    pRes->context.iFix = 0; // means dynamic size

    CseObjectRefs[dtDict]++;
    return (CseObj) &pRes->context;
}

CseObj CseDict_new(const TEntryArray& entry)
{
    TEntryArray newDict = TEntryArray(entry);

    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtDict;
    pRes->context.entry = newDict.transfer(NULL);
    pRes->context.iFix = 0; // means dynamic size

    CseObjectRefs[dtDict]++;
    return (CseObj) &pRes->context;
}

CseObj CseDict_NewEx(TEntryArray& entry)
{
    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtDict;
    pRes->context.entry = entry.transfer(NULL);
    pRes->context.iFix = 0; // means dynamic size

    CseObjectRefs[dtDict]++;
    return (CseObj) &pRes->context;
}

CseObj CseDict_EntryValue(CseObj dict, CseObj key)
{
    TEntryArray *EntryArray = (TEntryArray *) &dict->entry;
    return EntryArray->get(key);
}

PEntryPoint CseDict_IdEntry(CseObj dict, const TCharArray& sId, TUint32 hash)
{
    TEntryArray *EntryArray = (TEntryArray *) &dict->entry;
    return EntryArray->idEntry(sId,hash);
}

CseObj CseDict_IdEntryValue(CseObj dict, const TCharArray& sId, TUint32 hash)
{
    TEntryArray *EntryArray = (TEntryArray *) &dict->entry;
    return EntryArray->getById(sId,hash);
}

CseObj CseDict_StolenSet_(CseObj dict, CseObj key, CseObj value)
{
    TEntryArray *pArray = (TEntryArray *) &dict->entry;

    if (value == dummy)              // set dummy
        pArray->set(key,CseNull);
    else if (value == NULL)          // delete it
        pArray->set(key,dummy);
    else pArray->set(key,value);
    Cse_DecRef(value);
    
    if (dict->iFix != 0 && pArray->len() > dict->iFix)
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("dict exceed fix size"));
    return value;
}

CseObj CseDict_StolenSet(CseObj dict, CseObj key, CseObj value)
{
    if (key == dummy)
        throw LOG_CSE_ERR(CSE_KEY_ERR,_T("dummy is invalid dict key"));
    return CseDict_StolenSet_(dict,key,value);
}

void CseDict_set(CseObj dict, CseObj key, CseObj value)
{
    if (key == dummy)
        throw LOG_CSE_ERR(CSE_KEY_ERR,_T("dummy is invalid dict key"));
    CseDict_StolenSet_(dict,key,Cse_IncRefEx(value));
}

CseObj CseDict_SetEx(CseObj dict, CseObj key, CseObj value)
{
    if (key == dummy)
        throw LOG_CSE_ERR(CSE_KEY_ERR,_T("dummy is invalid dict key"));

    TEntryArray *pArray = (TEntryArray *) &dict->entry;
    TCseObj ret;
    
    if (value == dummy)
        ret = pArray->setEx(key,CseNull);
    else if (value == NULL)
        ret = pArray->setEx(key,dummy);
    else ret = pArray->setEx(key,value);

    if (dict->iFix != 0 && pArray->len() > dict->iFix)
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("dict exceed fix size"));
    return Cse_IncRefEx(ret);
}

void CseDict_clear(CseObj dict)
{   // fix size dict also can clear (just clean context)
    // dynamic size dict will realloc buffer
    TEntryArray *pArray = (TEntryArray *) &dict->entry;
    pArray->clear();
}

void CseDict_assign(CseObj TargDict, const TEntryArray& SourDict)
{
    if (TargDict->iFix != 0)  // fix size dict
        throw LogIndexOutRangeErr(dtDict);

    TEntryArray *dTarg = (TEntryArray *)&TargDict->entry;
    *dTarg = SourDict;
}

void CseDict_assign(CseObj TargDict, CseObj SourDict)
{
    ASSERT_TRUE(SourDict != NULL);
    TEntryArray *dSour = (TEntryArray *)&SourDict->entry;
    CseDict_assign(TargDict,*dSour);
}

void CseDict_join(CseObj TargDict, const TEntryArray& SourDict)
{
    TEntryArray *dTarg = (TEntryArray *) &TargDict->entry;
    dTarg->join(SourDict);

    if (TargDict->iFix != 0 && dTarg->len() > TargDict->iFix)
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("dict exceed fix size"));
}

void CseDict_join(CseObj TargDict, CseObj SourDict)
{
    ASSERT_TRUE(SourDict != NULL);
    TEntryArray *dSour = (TEntryArray *) &SourDict->entry;
    CseDict_join(TargDict,*dSour);
}

CseObj CseDict_StolenBind(CseObj dict, CseObj value)
{
    ASSERT_TRUE(value != NULL);
    
    TEntryArray *pArray = (TEntryArray *) &dict->entry;
    pArray->bind(value);
    Cse_DecRef(value);
    return value;
}

void CseDict_bind(CseObj dict, CseObj value)
{
    TEntryArray *pArray = (TEntryArray *) &dict->entry;
    pArray->bind(value);
}

CseObj CseDict_GetBinding(CseObj dict)
{
    TEntryArray *pArray = (TEntryArray *) &dict->entry;
    return pArray->getBinding();
}

TBool CseDict_enumItem(CseObj dict, PEntryPoint& pEntry)
{
    TEntryArray *pArray = (TEntryArray *) &dict->entry;
    return pArray->enumItem(pEntry);
}

CseObj CseNotator_new(CseObj NotatorId)
{
    ASSERT_TRUE(NotatorId != NULL);
    TObjArray newBuff(1);

    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    
    int tp = Cse_type(NotatorId);
    if (tp >= dtNotator)
        pRes->DataType = dtNotator + dtNull;
    else pRes->DataType = dtNotator + tp;
    
    pRes->context.bValue = newBuff.transfer(NULL);
    pRes->context.bValue[0] = Cse_IncRefEx(NotatorId);
    pRes->context.iFix = 0;  // means dynamic size

    CseObjectRefs[dtNotator]++;
    return (CseObj) &pRes->context;
}

CseObj CseStrong_new(CseObj initVal, TInt flag)
{
    ASSERT_TRUE(initVal != NULL);
    
    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtStrong;
    pRes->context.vValue = Cse_IncRefEx(initVal);
    pRes->context.iFlag  = flag;

    CseObjectRefs[dtStrong]++;
    return (CseObj) &pRes->context;
}

CseObj CseStrong_StolenSet(CseObj strong, CseObj value)
{
    ASSERT_TRUE(value != NULL);

    CseObj v = strong->vValue;
    strong->vValue = value;
    Cse_DecRef(v);
    return value;
}

void CseStrong_set(CseObj strong, CseObj value)
{
    ASSERT_TRUE(value != NULL);

    CseObj v = strong->vValue;
    strong->vValue = Cse_IncRefEx(value);
    Cse_DecRef(v);
}

STATIC CseObj CseId_new_(const TCharArray& initVal, TUint32 hash)
{
    TCharArray newArray(initVal);

    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtId;
    pRes->context.sValue = newArray.transfer(NULL);
    pRes->context.hash = hash;

    CseObjectRefs[dtId]++;
    return (CseObj) &pRes->context;
}

STATIC CseObj CseId_NewEx_(TCharArray& initVal, TUint32 hash)
{
    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtId;
    pRes->context.sValue = initVal.transfer(NULL);
    pRes->context.hash = hash;

    CseObjectRefs[dtId]++;
    return (CseObj) &pRes->context;
}

CseObj CseId_new(const TCharArray& sValue)
{
    if (sValue.isEmpty())
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("ID can not empty"));

    TUint32 hash = sValue.hash();
    PEntryPoint pEntry = CseDict_IdEntry(_ExistIDs,sValue,hash);

    if (NULL != pEntry->value)
        return Cse_IncRefEx(pEntry->key);
    else
    {
        CseObj ret = CseId_new_(sValue,hash);
        CseDict_StolenSet_(_ExistIDs,ret,dummy);
        Cse_DecRef(ret);
        return ret;
    }
}

CseObj CseId_NewEx(TCharArray& sValue)
{
    if (sValue.isEmpty())
        throw LOG_CSE_ERR(CSE_SYSTEM_ERR,_T("ID can not empty"));

    TUint32 hash = sValue.hash();
    PEntryPoint pEntry = CseDict_IdEntry(_ExistIDs,sValue,hash);

    if (NULL != pEntry->value)
        return Cse_IncRefEx(pEntry->key);
    else
    {
        CseObj ret = CseId_NewEx_(sValue,hash);
        CseDict_StolenSet_(_ExistIDs,ret,dummy);
        Cse_DecRef(ret);
        return ret;
    }
}

CseObj CseWeak_new(CseObj initVal, TInt flag)
{
    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];

    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtWeak;
    pRes->context.vValue = initVal;
    pRes->context.iFlag  = flag;

    CseObjectRefs[dtWeak]++;
    return (CseObj) &pRes->context;
}

CseObj CseInstance_new()
{
    CSE_BASE_TYPE *pRes = (CSE_BASE_TYPE *) new char[sizeof(CSE_BASE_TYPE)];
    pRes->RefCount = 1;
    pRes->flags = 0;
    pRes->DataType = dtInstance;
    pRes->context.bValue = CseEmptyBuff.addr();
    pRes->context.iFix = 0;  // means dynamic size

    CseObjectRefs[dtInstance]++;
    return (CseObj) &pRes->context;
}

TBool CseFree_DoNothing(CseObj obj)
{
    return true; // do nothing
}

TBool CseFree_DirectReturn(CseObj obj)
{
    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    delete []pBase;
    return true;
}

TBool CseFree_ReturnSBuff(CseObj obj)
{
    TCharArray s;
    s.transfer(obj->sValue);

    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    delete []pBase;
    return true;
}

TBool CseFree_ReturnTValue(CseObj obj)
{
    TIntArray t;
    t.transfer(obj->tValue);

    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    delete []pBase;
    return true;
}

TBool CseFree_ReturnBValue(CseObj obj)
{
    TObjArray b;
    b.transfer(obj->bValue);

    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    delete []pBase;
    return true;
}

TBool CseFree_ReturnDict(CseObj obj)
{
    TEntryArray d;
    d.transfer(obj->entry);

    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    delete []pBase;
    return true;
}

TBool CseFree_ReturnInstance(CseObj obj)
{
    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    pBase->RefCount++;  // protect CseInstance_free call

    try
    {
        CseInstance_free(obj);
    }
    catch(...)
    {
        pBase->RefCount--;
        throw;
    }
    pBase->RefCount--;

    if (0 == pBase->RefCount)
    {
        TObjArray b;
        b.transfer(obj->bValue);

        CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
        delete []pBase;
        return true;
    }
    else return false;
}

TBool CseFree_ReturnId(CseObj obj)
{
    Cse_SpecialFree(_ExistIDs->entry,obj,obj->hash);

    TCharArray s;
    s.transfer(obj->sValue);

    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    delete []pBase;
    return true;
}

TBool CseFree_ReturnStrong(CseObj obj)
{
    CseObj v = obj->vValue;
    obj->vValue = dummy;
    Cse_DecRef(v);

    CSE_BASE_TYPE *pBase = (CSE_BASE_TYPE *) ((char *)obj - CSEOBJ_INNER_OFFSET);
    delete []pBase;
    return true;
}

// only called when exit
void Cse_free(CseObj value, TBool recursive)
{
    int tp = Cse_type(value);

    if (tp == dtBuff || tp >= dtNotator)
    {
        if (recursive)
        {
            if (! Cse_OptionOn(value,CSEOBJ_FREE_FLAG))
            {
                Cse_SetOption(value,CSEOBJ_FREE_FLAG);
                int iLen = CSE_ARRAY_LEN(value->bValue);
                for (int iCount = 0; iCount < iLen; iCount++)
                {
                    CseObj v = value->bValue[iCount];
                    value->bValue[iCount] = dummy;
                    Cse_free(v,true);
                }
                Cse_ClearOption(value,CSEOBJ_FREE_FLAG);
            }
        }
        else CseBuff_clear(value);
    }

    else if (tp == dtDict)
    {
        if (recursive)
        {
            if ( ! Cse_OptionOn(value,CSEOBJ_FREE_FLAG) )
            {
                Cse_SetOption(value,CSEOBJ_FREE_FLAG);

                CSE_DICT_EXT *pDictExt = (CSE_DICT_EXT *)((char *)value->entry - sizeof(CSE_DICT_EXT));
                TEntryArray *pArray = (TEntryArray *) &value->entry;
                PEntryPoint pEntry = NULL;
                while (pArray->enumItem(pEntry))
                {
                    CseObj v = pEntry->value;
                    CseObj v2 = pEntry->key;
                    pEntry->key = dummy;
                    pEntry->value = NULL;
                    pDictExt->count--;
                    Cse_free(v,true);
                    Cse_free(v2,true);
                }

                CseObj v = Cse_IncRefEx(pArray->getBinding());
                if (v != dummy)
                {   // in most case, dict binding is dummy
                    pArray->bind(dummy);
                    Cse_free(v,true);
                }

                Cse_ClearOption(value,CSEOBJ_FREE_FLAG);
            }
        }
        else CseDict_clear(value);
    }

    else if (tp == dtStrong)
    {
        CseObj v = value->vValue;
        value->vValue = dummy;
        if (recursive)
          Cse_free(v,true);
        else Cse_DecRef(v);
    }

    Cse_DecRef(value);
}

// Following define register table API
//==============================================================================
STATIC TBool AdjustSegment(const TCharArray& key, TCharArray& seg)
{
    seg = key;
    int iLen = seg.len();
    if (iLen <= 0) return false;

    for (int i = 0; i < iLen; i++)
    {
        TXchar ch = seg[i];
        TXchar offset = _T('a') - _T('A');
        if (ch >= _T('a') && ch <= _T('z'))  // uppercase
            seg[i] = ch - offset;
        else if (_T('\\') == ch)             // chang "\" to "/"
            seg[i] = _T('/');
    }

    if (_T('/') == seg[iLen-1])              // remove last "/"
    {
        seg.truncate(iLen-1);
        return iLen > 1;
    }
    return true;
}

CseObj CseRegist_get(const TCharArray& key)
{
    TCharArray seg;
    if (! AdjustSegment(key,seg))
        return NULL;
    return CseDict_IdEntryValue(CseRegistTable,seg,seg.hash());
}

extern "C" {
CSE_IMPEXP_IN CseObj Cse_GetRegister(const TXchar *name)
{   // define C style API for easy accessing dll
    return CseRegist_get(name);
}
} // end of extern "C"

TBool CseRegist_exist(const TCharArray& key)
{
    return NULL != CseRegist_get(key);
}

CseObj CseRegist_StolenSet(const TCharArray& key, CseObj value)
{
    TCharArray seg;
    if (! AdjustSegment(key,seg))
    {
        Cse_DecRef(value);
        return dummy;
    }

    CseObj id = CseId_new(seg);
    CseDict_StolenSet(CseRegistTable,id,value);
    Cse_DecRef(id);

    return value;
}

CseObj CseRegist_set(const TCharArray& key, CseObj value)
{
    return CseRegist_StolenSet(key,Cse_IncRefEx(value));
}

void CseRegist_delete(const TCharArray& key)
{
    TCharArray seg;
    if (! AdjustSegment(key,seg)) return;

    CseObj id = CseId_new(seg);
    CseDict_StolenSet(CseRegistTable,id,NULL);
    Cse_DecRef(id);
}

CseObj CseRegist_StolenHold(CseObj value)
{
    int tp = Cse_type(value);
    if (dtInstance == tp)
    {   // holding object is automatic free, instance should free by manual before system exit
        Cse_DecRef(value);
        throw LOG_CSE_ERR(CSE_SYNTAX_ERR,_T("register can not hold instance"));
    }
    return CseBuff_StolenAppend(CsePreserves,value);
}

void CseRegist_hold(CseObj value)
{
    CseRegist_StolenHold(Cse_IncRefEx(value));
}

#ifndef CLOSE_REF_CHECK
  TInt32 GlobalCharArrayCount = 0;
#endif

// Following define module init and exit
//==============================================================================
void BaseTypes_init(void)
{
#ifndef CLOSE_REF_CHECK
    extern TInt32 TotalCharArrayCount;
    GlobalCharArrayCount = TotalCharArrayCount;
#endif

    _ExistIDs = CseDict_new();

    for (int i = 0; i <= dtNotator; i++)
        _FreeObjProc[i] = CseFree_DoNothing;

    _FreeObjProc[dtInt]      = CseFree_DirectReturn;
    _FreeObjProc[dtWint]     = CseFree_DirectReturn;
    _FreeObjProc[dtFloat]    = CseFree_DirectReturn;
    _FreeObjProc[dtStr]      = CseFree_ReturnSBuff;
    _FreeObjProc[dtTier]     = CseFree_ReturnTValue;
    _FreeObjProc[dtBuff]     = CseFree_ReturnBValue;
    _FreeObjProc[dtDict]     = CseFree_ReturnDict;
    _FreeObjProc[dtInstance] = CseFree_ReturnInstance;
    _FreeObjProc[dtId]       = CseFree_ReturnId;
    _FreeObjProc[dtStrong]   = CseFree_ReturnStrong;
    _FreeObjProc[dtWeak]     = CseFree_DirectReturn;
    _FreeObjProc[dtNotator]  = CseFree_ReturnBValue;

    CseRegistTable    = CseDict_new();
    CsePreserves      = CseBuff_new(0);

    CseNull = CseBuff_StolenAppend(CsePreserves,CseInstance_new());
    
    CseTypeStrFunc    = CseRegist_StolenSet(_T("KERNEL/TYPE_STR_FUNC"),CseInt_new(0));
    CseInstFreeFunc   = CseRegist_StolenSet(_T("KERNEL/FREE_FUNC"),CseInt_new(0));
    CseInstCmpFunc    = CseRegist_StolenSet(_T("KERNEL/CMP_FUNC"),CseInt_new(0));
    CseInstEqualFunc  = CseRegist_StolenSet(_T("KERNEL/EQU_FUNC"),CseInt_new(0));
    CseInstStrFunc    = CseRegist_StolenSet(_T("KERNEL/STR_FUNC"),CseInt_new(0));
    CseInstBeStrFunc  = CseRegist_StolenSet(_T("KERNEL/BESTR_FUNC"),CseInt_new(0));
    CseInstAsKeyFunc  = CseRegist_StolenSet(_T("KERNEL/ASKEY_FUNC"),CseInt_new(0));
    CseInstMapVarFunc = CseRegist_StolenSet(_T("KERNEL/MAPVAR_FUNC"),CseInt_new(0));
    CseLogErrorStack  = CseRegist_StolenSet(_T("KERNEL/LOGERR_FUNC"),CseInt_new(0));

    CseEmptySpace   = CseDict_new(8);
    CseThreadStacks = CseDict_new(8);
    CseTraceStack   = CseBuff_new(0);

    AssertIsReady = true;
}

STATIC void CleanRegistTable()
{
    Cse_IncRef(CseRegistTable);
    Cse_free(CseRegistTable,true);
    Cse_IncRef(CsePreserves);
    Cse_free(CsePreserves,true);
}

#if defined(__VISUALC__) || defined(__MINGW32__)
  #include <windows.h>
#endif

void BaseTypes_exit(void)
{
    AssertIsReady = false;

    // clean context of regist table
    if (__CheckRefCount)
        CleanRegistTable();
    else
    {
        try
        {
            CleanRegistTable();
        }
        catch(...) {}
    }

    // free space system, regist table, ID-name buffer
    try
    {   // free space system
        Cse_free(CseMainModule,true);
        Cse_free(CseBltinModule,true);
        Cse_free(CseEmptySpace,true);
        Cse_free(CseThreadStacks,true);

        // free regist table
        Cse_DecRef(CseRegistTable);
        Cse_DecRef(CsePreserves);

        // free trace stack
        CseBuff_clear(CseTraceStack);
        Cse_DecRef(CseTraceStack);

        // free ID-name buffer
        Cse_DecRef(_ExistIDs);
    }
    catch(...) {}
    
    // wholely exit CSE kernel and try check reference count
    TXchar MsgBuff[1024] = {'\0'};
    if (__CheckRefCount)
    {
        TCharArray sErr;
        for (int i = 0; i <= dtNotator; i++)
        {
            if (CseObjectRefs[i] != 0)
                sErr += TCharArray::format(_T("%s RefCount unbalance:%d\n"),Cse_GetTypeName(i),CseObjectRefs[i]);
        }

        if (! sErr.isEmpty())
            LOG_MSG(_T("%s"),sErr.addr());

#ifndef CLOSE_REF_CHECK
        {
            extern TInt32 TotalIntObjCount;
            extern TInt32 TotalWintObjCount;
            extern TInt32 TotalFloatObjCount;
            extern TInt32 TotalCharArrayCount;
            extern TInt32 TotalIntArrayCount;
            extern TInt32 TotalObjArrayCount;
            extern TInt32 TotalEntryArrayCount;
            extern TInt32 TotalCseObjCount;

            TXchar buff[256];
            SPRINTF(buff,_T("existing TIntObj: %d\n"),TotalIntObjCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
            SPRINTF(buff,_T("existing TWintObj: %d\n"),TotalWintObjCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
            SPRINTF(buff,_T("existing TFloatObj: %d\n"),TotalFloatObjCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);

            SPRINTF(buff,_T("existing TCharArray: %d\n"),TotalCharArrayCount - GlobalCharArrayCount - 1);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
            SPRINTF(buff,_T("existing TIntArray: %d\n"),TotalIntArrayCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
            SPRINTF(buff,_T("existing TObjArray: %d\n"),TotalObjArrayCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
            SPRINTF(buff,_T("existing TEntryArray: %d\n"),TotalEntryArrayCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
            SPRINTF(buff,_T("existing TCseObj: %d\n"),TotalCseObjCount);
            STRCAT(MsgBuff,buff); LOG_MSG(buff);
        }
#endif
    }
    else SPRINTF(MsgBuff,_T("application exiting"));

    if ( __HitBeforeExit )
    {
#if defined(__VISUALC__) || defined(__MINGW32__)
  #ifdef WINCE
        MessageBox(NULL,MsgBuff,_T("reference count"),MB_OK);
  #else
        MessageBox(NULL,MsgBuff,_T("reference count"),MB_OK | MB_SYSTEMMODAL);
  #endif
#else
        TXchar buff[256];
        SPRINTF(buff,_T("input 'exit' to quit\n"));
        FGETS(buff,256,stdin);
#endif
    }    
}
